local propagation = {}

local ELEMENT_MAX_NUMBER = 3
local VALUE_MAX_LENGTH = 128

local Util = require("skywalking.util")
local encode_base64 = Util.encode_base64
local decode_base64 = Util.decode_base64

local fromSW8Correlation = function(value)
    local context = {}

    if value == nil or #value == 0 then
        return context
    end

    local data = Util.split(value, ",")
    if #data == 0 then
        return context
    end

    for i, per_data in ipairs(data) do
        if #data > ELEMENT_MAX_NUMBER then
            return context
        end

        local parts = Util.split(per_data, ":")
        if #parts == 2 then
            local key = decode_base64(parts[1])
            local value = decode_base64(parts[2])

            context[key] = value
        end
    end

    return context
end

local fromSW8Value = function(value)
    local parts = Util.split(value, '-')
    if #parts ~= 8 then
        return nil
    end

    return parts
end

propagation.DecodeSW8 = function(segment_ref, header, carrier)
    local value = carrier[header]
    if value then
        local parts = fromSW8Value(value)
        if parts then
            local sample = tonumber(parts[1]) or 1
            local trace_id = decode_base64(parts[2])
            local segment_id = decode_base64(parts[3])
            local span_id = tonumber(parts[4])
            local parent_service = decode_base64(parts[5])
            local parent_service_instance = decode_base64(parts[6])
            local parent_endpoint = decode_base64(parts[7])
            local address_used_at_client = decode_base64(parts[8])

            segment_ref.trace_id = trace_id
            segment_ref.sample = sample
            segment_ref.parent_segment_id = segment_id
            segment_ref.parent_span_id = span_id
            segment_ref.parent_service = parent_service
            segment_ref.parent_endpoint = parent_endpoint
            segment_ref.address_used_at_client = address_used_at_client
            segment_ref.parent_service_instance = parent_service_instance
            
            return true
        end
    end

end

propagation.DecodeSW8Correlation = function(correlation_context, header, carrier)
    local value = carrier[header]
    if value then
        local correlation = fromSW8Correlation(value)
        correlation_context.correlation = correlation    
    end
end

propagation.EncodeSW8 = function(ref, header, injector)
    local encodedRef = tostring(ref.sample or 1)
            .. '-' .. encode_base64(ref.trace_id)
            .. '-' .. encode_base64(ref.segment_id)
            .. '-' .. ref.span_id
            .. '-' .. encode_base64(ref.parent_service)
            .. '-' .. encode_base64(ref.parent_service_instance)
            .. '-' .. encode_base64(ref.parent_endpoint)
            .. '-' .. encode_base64(ref.address_used_at_client)
    -- ngx.log(ngx.ERR, "EncodeSW8", encodedRef)
    injector(header, encodedRef)
end

propagation.EncodeSW8Correlation = function(correlation_context, header, injector)
    if correlation_context.correlation and next(correlation_context.correlation) then
        local encoded = ''
        for name, value in pairs(correlation_context.correlation) do
            if #encoded > 0 then
                encoded = encoded .. ','
            end

            encoded = encoded .. encode_base64(name) .. ':' .. encode_base64(value)
        end
        -- ngx.log(ngx.ERR, "EncodeSW8Correlation", encoded)
        injector(header, encoded)
    end
end

return propagation
